package com.joplus.housekeeper.xmpp;

import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.Looper;
import android.text.format.Time;
import android.util.Base64;
import android.util.Log;

import com.google.gson.Gson;
import com.hyphenate.chat.EMMessage;
import com.hyphenate.chat.EMTextMessageBody;
import com.hyphenate.chatuidemo.DemoApplication;

import com.hyphenate.chatuidemo.ui.ChatActivityNew;
import com.hyphenate.chatuidemo.ui.ChatFragment;
import com.hyphenate.chatuidemo.ui.MainActivity;
import com.hyphenate.chatuidemo.ui.SplashActivity;
import com.hyphenate.easeui.controller.EaseUI;
import com.hyphenate.easeui.model.EaseNotifier;
import com.hyphenate.easeui.ui.EaseChatFragment;
import com.hyphenate.util.ImageUtils;
import com.joplus.housekeeper.bean.LoginResult;
import com.joplus.housekeeper.bean.MessageRecordListBean;
import com.joplus.housekeeper.bean.XmppMessage;
import com.joplus.housekeeper.bean.XmppUser;
import com.joplus.housekeeper.core.Config;
import com.joplus.housekeeper.utils.Imageutils;
import com.joplus.housekeeper.utils.RealmHelper;
import com.joplus.housekeeper.utils.StringUtils;
import com.joplus.housekeeper.utils.T;

import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.ReconnectionManager;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.SmackException.NotLoggedInException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.chat.ChatManagerListener;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.packet.DefaultExtensionElement;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.delay.packet.DelayInformation;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.filetransfer.FileTransferListener;
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
import org.jivesoftware.smackx.filetransfer.FileTransferRequest;
import org.jivesoftware.smackx.filetransfer.IncomingFileTransfer;
import org.jivesoftware.smackx.filetransfer.OutgoingFileTransfer;
import org.jivesoftware.smackx.iqregister.AccountManager;
import org.jivesoftware.smackx.muc.HostedRoom;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.MultiUserChatManager;
import org.jivesoftware.smackx.offline.OfflineMessageManager;
import org.jivesoftware.smackx.receipts.DeliveryReceiptManager;
import org.jivesoftware.smackx.receipts.DeliveryReceiptRequest;
import org.jivesoftware.smackx.receipts.ReceiptReceivedListener;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Handler;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import io.realm.RealmResults;


public class SmackManager {
    private static final String TAG = "SmackManager";
    /**
     * Xmpp服务器地址
     */
    private final String SERVER_IP = Config.XMPP_HOST;
    /**
     * Xmpp 服务器端口
     */
    private final int PORT = Config.XMPP_PROT;
    /**
     * 服务器名称
     */
    private final String SERVER_NAME = Config.XMPP_SERVICE;
    /**
     * 客服名称
     */
    private String CUSTOMER_NAME;

    /**
     * 接受都的消息发送者
     */
    private String from;

    /**
     *
     */


    private static volatile SmackManager sSmackManager;
    /**
     * 连接
     */
    private XMPPTCPConnection mConnection;
    private String body;
    private DeliveryReceiptManager drm;

    private SmackManager() {

        this.mConnection = connect();
    }

    /**
     * 获取操作实例
     *
     * @return
     */
    public static SmackManager getInstance() {

        if (sSmackManager == null) {
            synchronized (SmackManager.class) {
                if (sSmackManager == null) {
                    sSmackManager = new SmackManager();
                }
            }
        }
        return sSmackManager;
    }

    /**
     * 连接服务器
     *
     * @return
     */
    private XMPPTCPConnection connect() {

        try {
            SmackConfiguration.setDefaultPacketReplyTimeout(10000);
            XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
                    //是否开启安全模式
                    .setSecurityMode(XMPPTCPConnectionConfiguration.SecurityMode.disabled)
                    //服务器名称
                    .setServiceName(SERVER_NAME)
                    .setHost(SERVER_IP)//服务器IP地址
                    //服务器端口
                    .setPort(PORT)
                    //是否开启压缩
                    .setCompressionEnabled(false)
                    //开启调试模式
                    .setDebuggerEnabled(true).build();
            XMPPTCPConnection connection = new XMPPTCPConnection(config);
            ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
            reconnectionManager.disableAutomaticReconnection();//允许自动重连
            //      reconnectionManager.setFixedDelay(2);//重连间隔时间
            connection.addConnectionListener(new SmackConnectionListener());//连接监听
            connection.connect();

            DeliveryReceiptManager.getInstanceFor(connection).addReceiptReceivedListener(new ReceiptReceivedListener() {
                @Override
                public void onReceiptReceived(String fromJid, String toJid, String receiptId, Stanza receipt) {
                    Log.e(TAG, "onReceiptReceived: " + receipt.toXML());
                }
            });
            connection.addAsyncStanzaListener(new StanzaListener() {
                @Override
                public void processPacket(Stanza packet) throws NotConnectedException {

                    Message packet1 = (Message) packet;
                    ExtensionElement extension = packet1.getExtension("extension", "urn:xmpp:joplus:extension");

                }
            }, new StanzaFilter() {
                @Override
                public boolean accept(Stanza stanza) {
                    return stanza instanceof Message;
                }
            });

            return connection;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 登陆
     *
     * @param username 用户账号
     * @param password 用户密码
     * @return
     * @throws Exception
     */
    public LoginResult login(String username, String password) {

        try {
            if (!isConnected()) {
                throw new IllegalStateException("服务器断开，请先连接服务器");
            }
            mConnection.login(username, password);
            XmppUser user = new XmppUser(username, password);
            user.setNickName(getAccountName());
            return new LoginResult(user, true);
        } catch (Exception e) {
            return new LoginResult(false, e.getMessage());
        }
    }

    public XMPPTCPConnection getConnection() {

        if (!isConnected() || mConnection == null) {
            connect();
        }
        return mConnection;
    }

    /**
     * 注销
     *
     * @return
     */
    public boolean logout() {

        if (!isConnected()) {
            return false;
        }
        try {
            mConnection.instantShutdown();
            return true;
        } catch (Exception e) {
            Log.e(TAG, "logout failure");
            return false;
        }
    }

    /**
     * 删除当前登录的用户信息(从服务器上删除当前用户账号)
     *
     * @return
     */
    public boolean deleteUser() {

        if (!isConnected()) {
            return false;
        }
        try {
            AccountManager.getInstance(mConnection).deleteAccount();//删除该账号
            return true;
        } catch (NoResponseException | XMPPErrorException
                | NotConnectedException e) {
            return false;
        }
    }

    /**
     * 注册用户信息
     *
     * @param username   账号
     * @param password   账号密码
     * @param attributes 账号其他属性，参考AccountManager.getAccountAttributes()的属性介绍
     * @return
     */
    public boolean registerUser(String username, String password, Map<String, String> attributes) {

        if (!isConnected()) {
            return false;
        }
        try {
            AccountManager.getInstance(mConnection).createAccount(username, password, attributes);
            return true;
        } catch (NoResponseException | XMPPErrorException
                | NotConnectedException e) {
            Log.e(TAG, "register failure");
            return false;
        }
    }

    /**
     * 修改密码
     *
     * @param newpassword 新密码
     * @return
     */
    public boolean changePassword(String newpassword) {

        if (!isConnected()) {
            return false;
        }
        try {
            AccountManager.getInstance(mConnection).changePassword(newpassword);
            return true;
        } catch (NoResponseException | XMPPErrorException | NotConnectedException e) {
            Log.e(TAG, "change password failure");
            return false;
        }
    }

    /**
     * 断开连接，注销
     *
     * @return
     */
    public boolean disconnect() {

        if (!isConnected()) {
            return false;
        }
        mConnection.disconnect();
        return true;
    }

    /**
     * 更新用户状态
     *
     * @param code
     * @return
     */
    public boolean updateUserState(int code) {

        if (!isConnected()) {
            throw new NullPointerException("服务器连接失败，请先连接服务器");
        }
        try {
            Presence presence;
            switch (code) {
                case 0://设置在线
                    presence = new Presence(Presence.Type.available);
                    presence.setMode(Presence.Mode.available);
                    mConnection.sendStanza(presence);
                    break;
                case 1://设置Q我吧
                    presence = new Presence(Presence.Type.available);
                    presence.setMode(Presence.Mode.chat);
                    mConnection.sendStanza(presence);
                    break;
                case 2://设置忙碌
                    presence = new Presence(Presence.Type.available);
                    presence.setMode(Presence.Mode.dnd);
                    mConnection.sendStanza(presence);
                    break;
                case 3://设置离开
                    presence = new Presence(Presence.Type.available);
                    presence.setMode(Presence.Mode.away);
                    mConnection.sendStanza(presence);
                    break;
                case 4://设置隐身
                    //                Roster roster = connection.getRoster();
                    //                Collection<RosterEntry> entries = roster.getEntries();
                    //                for (RosterEntry entry : entries) {
                    //                    presence = new Presence(Presence.Type.unavailable);
                    //                    presence.setStanzaId(Stanza.ID_NOT_AVAILABLE);
                    //                    presence.setFrom(connection.getUser());
                    //                    presence.setTo(entry.getUser());
                    //                    connection.sendStanza(presence);
                    //                }
                    //                // 向同一用户的其他客户端发送隐身状态
                    //                presence = new Presence(Presence.Type.unavailable);
                    //                presence.setStanzaId(Packet.ID_NOT_AVAILABLE);
                    //                presence.setFrom(connection.getUser());
                    //                presence.setTo(StringUtils.parseBareAddress(connection.getUser()));
                    //                connection.sendStanza(presence);
                    break;
                case 5://设置离线
                    presence = new Presence(Presence.Type.unavailable);
                    mConnection.sendStanza(presence);
                    break;
                default:
                    break;
            }
            return true;
        } catch (NotConnectedException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 是否连接成功
     *
     * @return
     */
    private boolean isConnected() {

        if (mConnection == null) {
            sSmackManager = new SmackManager();
        }
        if (mConnection == null) {
            return false;
        }
        if (!mConnection.isConnected()) {
            try {
                mConnection.connect();
                return true;
            } catch (SmackException | IOException | XMPPException e) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取账户昵称
     *
     * @return
     */
    public String getAccountName() {

        if (isConnected()) {
            try {
                return AccountManager.getInstance(mConnection).getAccountAttribute("name");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        throw new NullPointerException("服务器连接失败，请先连接服务器");
    }

    /**
     * 获取账户所有属性信息
     *
     * @return
     */
    public Set<String> getAccountAttributes() {

        if (isConnected()) {
            try {
                return AccountManager.getInstance(mConnection).getAccountAttributes();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        throw new NullPointerException("服务器连接失败，请先连接服务器");
    }

    /**
     * 创建聊天窗口
     *
     * @param jid 好友的JID
     * @return
     */
    public Chat createChat(String jid) {

        if (isConnected()) {
            ChatManager chatManager = ChatManager.getInstanceFor(mConnection);
            return chatManager.createChat(jid);
        }
        throw new NullPointerException("服务器连接失败，请先连接服务器");
    }

    /**
     * 获取聊天对象管理器
     *
     * @return
     */
    public ChatManager getChatManager() {

        if (isConnected()) {
            ChatManager chatManager = ChatManager.getInstanceFor(mConnection);
            return chatManager;
        }
        return null;
        //  throw new NullPointerException("服务器连接失败，请先连接服务器");
    }

    /**
     * 获取当前登录用户的所有好友信息
     *
     * @return
     */
    public Set<RosterEntry> getAllFriends() {

        if (isConnected()) {
            return Roster.getInstanceFor(mConnection).getEntries();
        }
        throw new NullPointerException("服务器连接失败，请先连接服务器");
    }

    /**
     * 获取指定账号的好友信息
     *
     * @param user 账号
     * @return
     */
    public RosterEntry getFriend(String user) {

        if (isConnected()) {
            return Roster.getInstanceFor(mConnection).getEntry(user);
        }
        throw new NullPointerException("服务器连接失败，请先连接服务器");
    }

    /**
     * 添加好友
     *
     * @param user      用户账号
     * @param nickName  用户昵称
     * @param groupName 所属组名
     * @return
     */
    public boolean addFriend(String user, String nickName, String groupName) {

        if (isConnected()) {
            try {
                Roster.getInstanceFor(mConnection).createEntry(user, nickName, new String[]{groupName});
                return true;
            } catch (NotLoggedInException | NoResponseException
                    | XMPPErrorException | NotConnectedException e) {
                return false;
            }
        }
        throw new NullPointerException("服务器连接失败，请先连接服务器");
    }

    /**
     * 获取聊天对象的Fully的jid值
     *
     * @param userName 用户账号
     * @return
     */
    public String getChatJid(String userName) {

        if (!isConnected()) {
            throw new NullPointerException("服务器连接失败，请先连接服务器");
        }
        return userName + "@" + mConnection.getServiceName();
    }

    /**
     * Jid The fully qualified jabber ID (i.e. full JID) with resource of the user
     *
     * @param userName
     * @return
     */
    public String getFullJid(String userName) {

        if (!isConnected()) {
            throw new NullPointerException("服务器连接失败，请先连接服务器");
        }
        //  return userName + "@" + mConnection.getServiceName() + "/" + XMPP_CLIENT;
        return userName + "@" + mConnection.getServiceName();
    }

    /**
     * 获取文件传输的完全限定Jid The fully qualified jabber ID (i.e. full JID) with resource of the user to
     * send the file to.
     *
     * @param userName 用户名，也就是RosterEntry中的user
     * @return
     */
    public String getFileTransferJid(String userName) {

        return getFullJid(userName);
    }

    /**
     * 获取发送文件的发送器
     * <p>
     * 一个完整的jid(如：laohu@192.168.0.108/Smack，后面的Smack应该客户端类型，不加这个会出错)
     *
     * @return
     */
    public OutgoingFileTransfer getSendFileTransfer() {

        if (isConnected()) {
            return FileTransferManager.getInstanceFor(mConnection).createOutgoingFileTransfer(CUSTOMER_NAME + "@" + SERVER_NAME + "／Smack");
        }
        throw new NullPointerException("服务器连接失败，请先连接服务器");
    }

    public void offlineMessage(XMPPConnection connection) {
        OfflineMessageManager offlineMessageManager = new OfflineMessageManager(connection);
        try {
            List<Message> messages = offlineMessageManager.getMessages();
            for (Message message : messages) {
                String body = message.getBody();
                Log.e(TAG, "offlineMessage: " + body);
            }

        } catch (NoResponseException e) {
            e.printStackTrace();
        } catch (XMPPErrorException e) {
            e.printStackTrace();
        } catch (NotConnectedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加文件接收的监听
     *
     * @param fileTransferListener
     */
    public void addFileTransferListener(FileTransferListener fileTransferListener) {

        if (isConnected()) {
            FileTransferManager.getInstanceFor(mConnection).addFileTransferListener(fileTransferListener);
            return;
        }
        throw new NullPointerException("服务器连接失败，请先连接服务器");
    }


    public ServiceDiscoveryManager getServiceDiscoveryManager() {

        if (!isConnected()) {
            throw new NullPointerException("服务器连接失败，请先连接服务器");
        }
        return ServiceDiscoveryManager.getInstanceFor(mConnection);
    }

    /**
     * 发送消息
     *
     * @param message

     */

    public void send(final String message, final String userName, final String  msgId) {
        //   CUSTOMER_NAME = userName;
        if (StringUtils.isEmpty(message)) {
            return;
        }
        if (getChatManager() == null) {
            Observable.just("连接出现错误").subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
                @Override
                public void accept(String s) throws Exception {
                    Context context = DemoApplication.getInstance();
                    T.showLong(context, s);
                    Intent intent = new Intent(context, SplashActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    context.startActivity(intent);
                }
            });
        }
        Observable.just(message)
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<String>() {
                               @Override
                               public void accept(String s) {
                                   try {
                                       // getChatManager().createChat(userName + "@" + SERVER_NAME).sendMessage(message);
                                       Message smackMessage = new Message();
                                       SmackElement smackElement = new SmackElement();
                                       smackElement.setId(msgId);
                                       smackMessage.addExtension(smackElement);
                                       smackMessage.setBody(message);

                                       //    mConnection.sendStanza(smackMessage);
                                       getChatManager().createChat(userName + "@" + SERVER_NAME, new ChatMessageListener() {
                                           @Override
                                           public void processMessage(Chat chat, Message message) {
                                               Log.e("smack", "processMessage:" + message);

                                           }
                                       }).sendMessage(smackMessage);


                                   } catch (Exception e) {
                                       e.printStackTrace();
                                       Log.e("process", e.toString());
                                   }
                               }
                           }
                );
    }

    public void addFileListener() {
        FileTransferManager instanceFor = FileTransferManager.getInstanceFor(connect());
        instanceFor.addFileTransferListener(new FileTransferListener() {
            @Override
            public void fileTransferRequest(FileTransferRequest request) {
                IncomingFileTransfer accept = request.accept();
                try {
                    File skRoot = Environment.getExternalStorageDirectory();
                    accept.recieveFile(new File(skRoot, request.getFileName()));

                } catch (SmackException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 添加单聊消息全局监听
     */
    public void addMessageListener() {
        if (getChatManager() == null) {
            Observable.just("连接出现错误").subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
                @Override
                public void accept(String s) throws Exception {
                    Context context = DemoApplication.getInstance();
                    T.showLong(context, s);
                    Intent intent = new Intent(context, SplashActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    context.startActivity(intent);
                }
            });
        }


        if (getChatManager() != null) {
            getChatManager().addChatListener(new SmackChatManagerListener());
        }
    }


}
